import { isObject ,def} from "../utils/tool"
import {vueArrayMethods} from "./vue-array-methods"

/**对vue中data进行数据劫持 */
export function observe(data) {
    /**data不是对象直接返回 */
    if (!isObject(data)) return;

    /**响应式类 */
    new Observe(data);
}

/**处理data里面的每一个数据项 */
class Observe {
    constructor(data) {
        /**对于data里面的数据，如果不是数组时执行一步处理walk
         * 是数组是，数组里面不是对象的不用监控，对象监控,并且对Array的一些方法进行拦截
         */

         /**给data中所有数据添加一个__ob__属性，该属性为Observe这个实例 */
        def(data,'__ob__',this);

        if (Array.isArray(data)) {
            /**
             * 对数组进行单独处理，对数组里面的普通项不进行观察，只有当数组里面项为对象时才进行监听
             * 重写Array，对数组方法进行拦截
             */
            data.__proto__=vueArrayMethods;
            this.observeArray(data);
        } else {
            this.walk(data);
        }
    }
    /**一步处理data里面的数据
     * 一步处理时只处理对象
     */
    walk(data) {
        const keys = Object.keys(data);

        keys.forEach(key => {
            const value = data[key];

            /**核心-响应式处理
             * 用defineProperty对data里面的属性进行观察
             */
            defineReactive(data, key, value);
        });
    }
    /**Array响应式处理 */
    observeArray(data) {
        for (let i = 0, length = data.length; i < length; i++) {
            observe(data[i])
        }
    }
}

/**响应式处理data里面的数据 */
function defineReactive(data, key, value) {
    /**如果data里面数据项也是一个Object，需要递归处理 */
    observe(value);

    Object.defineProperty(data, key, {
        get() {
            return value;
        },
        set(newValue) {
            if (value === newValue) return;
            console.log('data of set');
            /**当用户给data里面的数据赋值时，要将新赋的值也做响应式处理 */
            observe(newValue);
            value = newValue;
        }
    })
}